

(define-derived-mode sql-ms-assist-ptv-mode sql-ms
  "Helps with finding details in procs and triggers. Derived from Sql-mode"
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

  
  (setq sql-ms-assist-pt-minor-mode-map (make-sparse-keymap));keymap, so certain key chords work to our advantage
  ;;What IS THIS? - Yes! we're defining a minor mode in the body of the derived mode.
  ;;because we only want the minor mode to be available when the derived mode is
  ;;activated. No doubt, there is a better, more correct way to do this.
  (define-minor-mode sql-ms-assist-ptv-minor-mode
    "Some shortcut keys and functions to help you quickly sift through a morass
of Stored Procedures and triggers relating to a table"
    nil " assist-ptv" sql-ms-assist-pt-minor-mode-map
    (define-key sql-ms-assist-pt-minor-mode-map '[M-right] 'smapmm-goto-point-in-proc)
    (define-key sql-ms-assist-pt-minor-mode-map '[M-left] 'smapmm-goto-other-buffer )
    (define-key sql-ms-assist-pt-minor-mode-map "\M-\r" 'smapmm-proc-process))
    
  ;ask the user which table they're looking for.
  (add-hook 'sql-ms-assist-ptv-minor-mode-hook 'smapmm-set-search-name)


  (setf *this-window* (selected-window))
  (setf *window-below* (next-window))
  (setf *search-str* nil)
  (setf *proc-name* "")
  (setf *current-proc* "")
  (setf *line-number* 0)
  (global-set-key '[M-left] 'smapmm-goto-other-buffer)

(defun sql-ms-assist-ptv-search-again ()
  (interactive)
  (smapmm-set-search-name))


(defmacro delta-wait (timeout selected-window next-window)
  `(let* ((safetylimit (make-symbol "sl")) (safetylimit ,timeout)
	  (this-window (make-symbol "tw")) (this-window ,selected-window)
	  (window-below (make-symbol "wb")) (window-below ,next-window)
	  (base-point (make-symbol "bp"))  (base-point (smapmm-max-point window-below this-window))
	  (REFERENCE-POINT (make-symbol "rp")) (REFERENCE-POINT base-point)
	  (point-now (make-symbol "pn")) (point-now 0)
	  (safetycount (make-symbol "sc")) (safetycount 0)
	  (iterator (make-symbol "i")) (iterator 0)
	  (loading (make-symbol "l")) (loading 1))
     (while (< safetycount safetylimit)
					;bit of trickery here, so we can simulate content going into the buffer
					; (if (and (< safetycount 10) (> safetycount 4))
					; (progn
					; (select-window window-below)
					; (insert "hello there\n")
					; (select-window this-window)))
					;trickery out
       (setf point-now (smapmm-max-point window-below this-window))
       (if (and (eq point-now REFERENCE-POINT) (> REFERENCE-POINT base-point))
	   (setf safetycount safetylimit))
       (setf REFERENCE-POINT point-now)
       (message "PROCESSING")
       (sleep-for 1)
       (incf safetycount))))


  (defun smapmm-set-search-name ()
    (interactive)
    (setf *search-str* (read-string "What's the name you want to look for? "))
    (setf *sp-name* (read-string "sp_findstring or sp_depends?"))
    (message (concat "QUERY SENT ->:" *sp-name* " " *search-str*))
    (smapmm-run-query (concat *sp-name* " " *search-str*))
    ;(move-sql-buffer-here)
    (setf *this-window*  (selected-window))
    (message (concat "*this-window* :" (prin1-to-string *this-window*)))
    (setf *window-below* (next-window))



(delta-wait 30 *this-window* *window-below*)

    
   ; (setf point-max 0)
   ; (setf point-delta 1)
   ; (setf safetycount 1)
   ; (while (and (> point-delta 0) (< safetycount 60))
   ;   (setf point-now (smapmm-max-point *window-below* *this-window*))
   ;   (setf point-delta (- point-now point-max))
   ;   (setf point-max point-now)
   ;   (incf safetycount)
   ;   (message (concat "Please Wait: PROCESSING (SafetyCount:" (number-to-string safetycount) "Delta:" (number-to-string  point-delta) ")"))
   ;   (sleep-for 5))

    (select-window *window-below*)
    (setf tmp-buf-contents (buffer-substring-no-properties (point-min) (point-max)))
    (message tmp-buf-contents)
    (select-window *this-window*)
    (insert tmp-buf-contents)
    (smapmm-clear-other-window *window-below* *this-window*)
   ; (beginning-of-buffer)
)


(defun sql-ms-assist-change-search-name ()
(interactive)
    (setf *search-str* (read-string "What's the name you want to look for? ")))


  (defun smapmm-matches-to-list (str)
    (let ((mypoint 0)
	  (safetycount 0)
	  (lst '()))
      (while (and (numberp mypoint) (< safetycount 100))
	(setf mypoint (search-forward str nil t))
	(incf safetycount)
	(if (and (numberp mypoint) (> (- mypoint (length str)) 0))
	    (progn
	      (beginning-of-line)
	      (setf mystart (point))
	      (end-of-line)
	      (setf myend (point))
	      (setf whole-match (buffer-substring-no-properties mystart myend))
	      (push (concat "line: " (number-to-string (line-number-at-pos)) " -> " (smapmm-chomp whole-match)) lst))))
      lst))

  (defun smapmm-place-list-below-this-line (lst)
    (setf mypointnow (point))
    (while (> (length lst) 0)
      (setf mymu (pop lst))
      (end-of-line)
      (newline)
      (insert "    ")
      (insert mymu))
    (goto-char mypointnow))

  (defun smapmm-search-for-matches-in-other-buffer (other-window this-window match-string)
    (select-window other-window)
    (smapmm-kill-blank-lines)
    (beginning-of-buffer)
    (setf my-matches '())
    (setf my-matches (smapmm-matches-to-list match-string))
    (select-window this-window)
    my-matches)


  (defun smapmm-run-query (qstr)
    (sql-send-string qstr)
    (sql-send-string "go"))


  (defun smapmm-clear-other-window (other-window this-window)
    (select-window other-window)
    (delete-region (point-min) (point-max))
    (select-window this-window))

  (defun smapmm-run (proc-name column-name)
    (smapmm-clear-other-window *window-below* *this-window*)
    (smapmm-run-query (concat "exec sp_helptext " proc-name))
    (setf *this-window* (selected-window))
    (setf *window-below* (next-window))
    ;(setf point-max 0)
    ;(setf point-delta 1)
    ;(setf safetycount 1)
    ;(while (and (> point-delta 0) (< safetycount 60))
    ;  (setf point-now (smapmm-max-point *window-below* *this-window*))
    ;  (setf point-delta (- point-now point-max))
    ;  (setf point-max point-now)
    ;  (incf safetycount)
    ;  (sleep-for 1))
(delta-wait 30 *this-window* *window-below*)
    (setf all-matches (smapmm-search-for-matches-in-other-buffer *window-below* *this-window* column-name))
    (setf all-matches (nreverse all-matches))
    (smapmm-place-list-below-this-line all-matches)
    (smapmm-clear-other-window *window-below* *this-window*))

  (defun smapmm-max-point (window-below this-window)
    (select-window window-below)
    (setf mymaxpoint (point-max))
    (select-window this-window)
    mymaxpoint)


					;okay, so when we're on a line, we need to be able to go to the line to get the context of everything.
  (defun smapmm-goto-point-in-proc ()
    (interactive)
    (setf mypointnow (point))
    (beginning-of-line)
    (re-search-forward "line: [0-9]+")
    (skip-syntax-backward "w_")
    (setf mystart (point))
    (skip-syntax-forward "w_")
    (setf myend (point))
    (setf whole-match (buffer-substring-no-properties mystart myend))
    (message (concat "line->" whole-match))
    (setf line-number (string-to-number whole-match))
    (message (concat "LINE->" (number-to-string line-number)))
    (search-backward ">>")		;so we get to the marker
    (re-search-forward "[a-zA-Z0-9_]+" nil t)
    (skip-syntax-backward "w_")
    (setf mystart (point))
    (skip-syntax-forward "w_")
    (setf myend (point))
    (goto-char mypointnow)
    (setf whole-match (buffer-substring-no-properties mystart myend))
    (setf proc-name whole-match)
    ;(setf point-max 0)
    ;(setf point-delta 1)
    ;(setf safetycount 1)
    (if (equal *current-proc* proc-name)
	(progn
	  (message "samesame")
	  (select-window *window-below*)
	  (smapmm-kill-blank-lines)
	  (goto-line line-number)
	  (search-forward *search-str*)
	  (skip-syntax-backward "w_")
	  )
      (progn
	(smapmm-clear-other-window *window-below* *this-window*)
	(setf *current-proc* proc-name)
	(smapmm-run-query (concat "exec sp_helptext " proc-name))
	;(while (and (> point-delta 0) (< safetycount 60))
	;  (setf point-now (smapmm-max-point *window-below* *this-window*))
	;  (setf point-delta (- point-now point-max))
	;  (setf point-max point-now)
	;  (incf safetycount)
	;  (sleep-for 1))
	(delta-wait 30 *this-window* *window-below*)
	(select-window *window-below*)
	(smapmm-kill-blank-lines)
	(goto-line line-number)
	(re-search-forward *search-str*)
	(skip-syntax-backward "w_"))))

  (defun smapmm-goto-other-buffer ()
    (interactive)
    (select-window *this-window*))

  (defun smapmm-proc-process ()
    (interactive)
    (skip-syntax-backward "w_")
    (insert ">> ")
    (setf mystart (point))
    (skip-syntax-forward "w_")
    (setf myend (point))
    (setf proc-name (buffer-substring-no-properties mystart myend))
    (message (concat "calling " proc-name " " *search-str*))
    (smapmm-run proc-name *search-str*))

  (defun smapmm-kill-blank-lines ()
    (interactive)
    (end-of-buffer)
    (while (re-search-backward "^[ ]+$" nil t)
      (beginning-of-line)
      (kill-line)))

  (defun smapmm-chomp (str)
    "This function has been stolen off the web
I think the right person should get credit for it
but I can't for the LIFE of me remember where I found it..."
    (let ((s (if (symbolp str)(symbol-name str) str)))
      (save-excursion
	(while (and
		(not (null (string-match "^\\( \\|\f\\|\t\\|\n\\)" s)))
		(> (length s) (string-match "^\\( \\|\f\\|\t\\|\n\\)" s)))
	  (setq s (replace-match "" t nil s)))
	(while (and
		(not (null (string-match "\\( \\|\f\\|\t\\|\n\\)$" s)))
		(> (length s) (string-match "\\( \\|\f\\|\t\\|\n\\)$" s)))
	  (setq s (replace-match "" t nil s))))
      s))	  

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  (select-window (previous-window))
  (sql-mode)
  (sql-ms-assist-ptv-minor-mode))
